package org.fin.framework.ioc.beans;

import org.fin.framework.ioc.annotation.Autowired;
import org.fin.framework.ioc.annotation.Component;
import org.fin.framework.ioc.annotation.Repository;
import org.fin.framework.ioc.annotation.Service;
import org.fin.framework.ioc.exception.BeanParseException;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;

/**
 * 负责读取解析bean的信息，用于封装BeanDefinition对象
 */
public class BeanDefinitionReader {

  private Class<?> beanCls;

  public BeanDefinitionReader(Class<?> beanCls) {
    this.beanCls = beanCls;
  }

  public List<DependencyDefinition> getDependencyDefinition() {
    List<DependencyDefinition> result = new ArrayList<>();

    Stream<Field> fields = getAutowiredFields();
    Stream<Method> methods = getAutowiredMethods();
    Constructor<?> constructor = getAutowiredConstructor();

    if (constructor != null) {
      DependencyDefinition dd = new DependencyDefinition();
      dd.setInjectTarget(constructor);
      result.add(dd);
    }

    List<DependencyDefinition> collected = Stream.concat(fields, methods)
        .collect(
            ArrayList::new,
            (list, member) -> {
              DependencyDefinition dd = new DependencyDefinition();
              dd.setInjectTarget(member);
              list.add(dd);
            },
            List::addAll
        );

    result.addAll(collected);
    return result;
  }

  public boolean isAbstract() {
    boolean isAbstract = Modifier.isAbstract(beanCls.getModifiers());
    boolean isInterface = beanCls.isInterface();
    return isAbstract || isInterface;
  }


  /**
   * 获取所有标注了@Autowired的成员属性的流
   * @return          标注了@Autowired的成员属性的流
   */
  private Stream<Field> getAutowiredFields() {
    return Arrays.stream(beanCls.getDeclaredFields())
        .filter(f -> f.isAnnotationPresent(Autowired.class));
  }

  /**
   * 获取标注了@Autowired的构造器，没有的话返回null，多于一个则抛错
   * @return          标注了@Autowired的构造器
   */
  private Constructor<?> getAutowiredConstructor() {
    Constructor<?>[] constructors = beanCls.getDeclaredConstructors();

    AtomicInteger count = new AtomicInteger(0);

    return Arrays.stream(constructors)
        .filter(c -> c.isAnnotationPresent(Autowired.class))
        .peek(c -> {
          count.getAndIncrement();
          if (count.get() > 1) {
            throw new BeanParseException("@Autowired标注的构造器不能多于一个");
          }

        })
        .findAny()
        .orElse(null);
  }

  /**
   * 获取所有标注了@Autowired的方法对象的流
   * @return          标注了@Autowired的方法对象的流
   */
  private Stream<Method> getAutowiredMethods() {
    return Arrays.stream(beanCls.getDeclaredMethods())
        .filter(m -> m.isAnnotationPresent(Autowired.class));
  }

  public String getBeanId() {
    Component component = beanCls.getDeclaredAnnotation(Component.class);
    Service service = beanCls.getDeclaredAnnotation(Service.class);
    Repository repository = beanCls.getDeclaredAnnotation(Repository.class);

    String beanId;
    if (component != null) {
      String value = component.value();
      beanId = parseValueToBeanId(value);
    }
    else if (service!= null) {
      String value = service.value();
      beanId = parseValueToBeanId(value);
    }
    else if (repository != null){
      String value = repository.value();
      beanId = parseValueToBeanId(value);
    }
    else {
      throw new BeanParseException("bean[" + beanCls.getName() + "]解析异常，原因：未找到bean注解");
    }

    return beanId;
  }

  private String parseValueToBeanId(String value) {
    String beanId;
    if (value.isBlank()) {
      String clsName = beanCls.getSimpleName();
      beanId = clsName.substring(0, 1).toLowerCase() + clsName.substring(1);
    }else {
      beanId = value;
    }
    return beanId;
  }


  public Class<?> getBeanCls() {
    return beanCls;
  }

}
